class Scope(object):
    ''' 使用这种类的模式来管理权限,可以不用频繁的请求Mysql,让页面速度更快
        当前管理权限的思路:在token中根据auth属性来保存用户的权限名(类名的字符串形式)
        使用endpoint来记录当前用户请求的api_name,并根据globals()函数拿到权限名对应的权限类
        使用类变量api_name_list,判断endpoint是否存在于list中,达到权限控制的目的'''
    allow_api = [] # api层权限
    allow_modules = [] # 模块层权限
    forbidden = [] # 禁止访问层权限

    def __add__(self, other):
        # 当前魔法方法可以让对象进行相加操作,可以让代码量更少,其实就是对list进行相加
        self.allow_api = self.allow_api + other.allow_api
        self.allow_api = list(set(self.allow_api)) # 将当前的list去重

        self.allow_modules = self.allow_modules + other.allow_modules
        self.allow_modules = list(set(self.allow_modules))

        self.forbidden = self.forbidden + other.forbidden
        self.forbidden = list(set(self.forbidden))


class UserScope(Scope):
    allow_api = ['v1.user+create_clent', 'v1.user+delete_user']


class AdminScope(Scope):
    allow_modules = ['v1.user', 'v1.token'] # 模块化权限,又可以节省大量的代码
    forbidden = ['v1.token+get_token']

    def __init__(self):
        ''' 假设一个项目有101个api,管理员可以全部访问,而用户可以访问100个
            如果直接在当前类中复制UserScope里的api_list,并加入可以访问的api_name,这样做法太lou了
            代码的可读性也不高,别人不能一眼看出两个角色访问视图函数的差别
            所以定义一个权限最低的类,将这个类的api_list添加到当前权限的api_list中
            我们只要定义当前类可以访问的api就行,这样可读性和代码量都将减少很多'''
        self + UserScope() # AdminScope.__add__(UserScope())


class SuperScope(Scope):
    ''' 如果有第三个权限更高的类出现,需要用到前面两个的合集
        可以添加两个类的list,使用链式调用的模式
        想法:都是list,既然是list就可以相加,所以不是有一个基础类,就只能用这个基础类
        关键是list可以相加,而不是类'''
    allow_modules = ['v1.tokrn', 'v1.user']

    def __init__(self):
        ''' 既然self可以调用add()方法,我们只要在add()内部返回self,就可以链式调用add()
            思维广度的重要性 '''
        self + UserScope() + AdminScope()


def is_in_scope(scope, endpoint):
    red_name, endpoint = endpoint.spilt('+')
    # globals会将当前模块的变量,类,函数等全部转成字典的方式存储起来
    scope = globals()[scope]() # 当前就是用scope当key,拿到类,实例化对象
    
    if endpoint in scope.forbidden: # 存在说明禁止访问
        return False
    if endpoint in scope.allow_api: # 存在说明可以访问
        return True
    # 如果红图名字是v1.user的话,当前对象可以访问所有user红图注册的视图函数
    if red_name in scope.allow_modules:
        return True
    else:
        return False
